/*
* $Id: FieldsValueManager.java 265 2011-02-07 23:13:07Z volok-aleksej@yandex.ru $
*
* Copyright 2008-2011 by Volokitin Alexey
* All rights reserved
*
*/
package apiary.db.managers;

import java.io.ByteArrayOutputStream;
import java.util.*;

import apiary.db.FieldsValueStore;
import apiary.db.FieldsValueStore.FieldsValueRecord;
import apiary.ui.journal.UserFieldForm.UserField;

/**
 * User's fields values manager
 * @author lexus
 */
public class FieldsValueManager
{
    /** instance class */
    private static FieldsValueManager instance = null;
    /**
     * Gets instance class
     * @return instance class
     */
    protected static FieldsValueManager getInstance() {
        return instance;
    }

    /** user's fields values database */
    private FieldsValueStore fieldsValueStore;
    /** maximal user's fields value identificator */
    private int maxIdFieldsValue;
    /** list of user's fields value */
    private Hashtable dbFieldsValue;

    /**
     * Constructor
     */
    public FieldsValueManager() {
        instance = this;
        fieldsValueStore = new FieldsValueStore();
        dbFieldsValue = new Hashtable();
        readFieldsValueStore();
    }

    /**
     * Calculates next value identificator
     * @return identificator
     */
    protected int nextIdRecord() {
        return maxIdFieldsValue + 1;
    }

    /**
     * Gets user's fields values on identificator
     * @param idFieldValue identificator of user's fields values
     * @return list of user's fields values
     */
    protected Vector getFieldsValue(int idFieldValue) {
        Vector vector = new Vector();
        Integer id = new Integer(idFieldValue);
        if(dbFieldsValue.containsKey(id))
            vector = (Vector) dbFieldsValue.get(id);
        return vector;
    }

    /**
     * Adds user's field value at list.
     * Data will be parsed and created new value object.
     * @param data binary data that describe user's field value
     * @param offset offset with  begin data
     */
    protected void addFieldValues(byte[] data, int offset) {
        while(offset != data.length) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            baos.write(data, offset, data.length - offset);
            FieldsValueRecord fieldsValueRecord =
                    (FieldsValueRecord) fieldsValueStore.getRecord();
            offset += fieldsValueRecord.setData(baos.toByteArray());
            addHashtableRecord(fieldsValueRecord.idRecord, fieldsValueRecord);
            if(maxIdFieldsValue < fieldsValueRecord.idRecord)
                maxIdFieldsValue = fieldsValueRecord.idRecord;
        }
    }

    /**
     * Adds user's field value at list.
     * Converts value to database format and adds at list.
     * @param field user field value
     * @param idRecord identificator of user's field value
     * @return binary data that describe value
     */
    protected byte[] addFieldValue(UserField field, int idRecord) {
        FieldsValueRecord fieldRecord = (FieldsValueRecord) fieldsValueStore.getRecord();
        fieldRecord.idRecord = idRecord;
        ConvertData.UserFieldToFieldsValue(field, fieldRecord);
        addHashtableRecord(idRecord, fieldRecord);
        return fieldRecord.getData();
    }

    /**
     * Changes user's field value at list.
     * Data will be parsed and changed value object.
     * @param data binary data that describe point
     * @param offset offset with  begin data
     */
    protected void changeFieldValues(byte[] data, int offset) {
        while(offset != data.length) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            baos.write(data, offset, data.length - offset);
            FieldsValueRecord fieldsValueRecord =
                    (FieldsValueRecord) fieldsValueStore.getRecord();
            fieldsValueRecord.setData(baos.toByteArray());
            FieldsValueRecord fieldValue =
                    getFieldValue(fieldsValueRecord.idRecord, fieldsValueRecord.nameField);
            if(fieldValue == null) {
                addHashtableRecord(fieldsValueRecord.idRecord, fieldValue);
                if(maxIdFieldsValue < fieldsValueRecord.idRecord)
                    maxIdFieldsValue = fieldsValueRecord.idRecord;
            }
            offset += fieldValue.setData(baos.toByteArray());
        }
    }

    /**
     * Changes user's field value at list.
     * Converts user's field value to database format and changes at list.
     * @param field user's field value
     * @param idRecord identificator of user's field value
     * @return binary data that describe vale
     */
    protected byte[] changeFieldValue(UserField field, int idRecord) {
        FieldsValueRecord fieldValue = getFieldValue(idRecord, field.nameField);
        if(fieldValue == null) {
            fieldValue = (FieldsValueRecord) fieldsValueStore.getRecord();
            fieldValue.idRecord = idRecord;
            addHashtableRecord(idRecord, fieldValue);
        }
        ConvertData.UserFieldToFieldsValue(field, fieldValue);
        return fieldValue.getData();
    }
    
    /**
     * Delete user's field value from list.
     * @param idRecord identificator of user's field value
     */
    protected void deleteValues(int idRecord) {
        dbFieldsValue.remove(new Integer(idRecord));
    }

    /**
     * Reads user's fields value database
     */
    private void readFieldsValueStore() {
        Enumeration fieldsValueEnum = fieldsValueStore.getRecordsEnumeration();
        do {
            if(!fieldsValueEnum.hasMoreElements())
                break;
            FieldsValueRecord record = (FieldsValueRecord) fieldsValueEnum.nextElement();
            addHashtableRecord(record.idRecord, record);
            if(maxIdFieldsValue < record.idRecord)
                maxIdFieldsValue = record.idRecord;
        } while(true);
    }

    /**
     * Adds user's fields value at list
     * @param idRec identificator of value
     * @param record user's fields value
     */
    private void addHashtableRecord(int idRec, FieldsValueRecord record) {
        Integer idRecord = new Integer(idRec);
        if(!dbFieldsValue.containsKey(idRecord))
            dbFieldsValue.put(idRecord, new Vector());
        Vector fieldsValue = (Vector) dbFieldsValue.get(idRecord);
        fieldsValue.addElement(record);
    }

    /**
     * Gets user's field value on idebtificator value and it's name
     * @param id identificator of value
     * @param name user's field name
     * @return user's field value
     */
    private FieldsValueRecord getFieldValue(int id, String name) {
        Vector fieldsValue = getFieldsValue(id);
        for (int i = 0; i < fieldsValue.size(); i++) {
            FieldsValueRecord fvRecord = (FieldsValueRecord) fieldsValue.elementAt(i);
            if(fvRecord.nameField.equals(name)) {
                return fvRecord;
            }
        }
        return null;
    }
}
